package com.biodiv.miracle.boot.conditional;

import com.biodiv.miracle.support.annotation.ConditionalOnMissingBean;
import com.biodiv.miracle.ioc.processor.InjectBeanPostProcessor;
import com.biodiv.miracle.support.utils.MiracleUtils;

import java.lang.reflect.Method;

/**
 * @Author: tianquan
 * @date: 2024-10-07  08:49
 * @Description: @ConditionalOnMissingBean注解解析器
 */
public class ConditionalOnMissingBeanPostProcessor implements InjectBeanPostProcessor {

    @Override
    public void inject(Object bean) {
        Class<?> aClass = bean.getClass();
        Method[] methods = aClass.getMethods();
        for (Method method : methods) {
            ConditionalOnMissingBean conditionalOnMissingBean = method.getAnnotation(ConditionalOnMissingBean.class);
            if (conditionalOnMissingBean == null) {
                continue;
            }
            // 该方法上有@ConditionalOnMissingBean，判断返回值在容器中是否存在，不存在才将该方法的返回值放入容器
            Class<?> returnType = method.getReturnType();
            Object object = MiracleUtils.getBean(returnType);
            if (object != null) {
                continue;
            }
            // 不存在，将方法的返回值放入容器
            method.setAccessible(true);
            // 获取方法要的参数数量
            int parameterCount = method.getParameterCount();
            // 方法参数数量
            Object[] args = new Object[parameterCount];
            // 有参方法 填充参数列表
            if (parameterCount > 0) {
                Class<?>[] parameterTypes = method.getParameterTypes();
                for (int i = 0; i < parameterCount; i++) {
                    args[i] = MiracleUtils.getBean(parameterTypes[i]);
                }
            }
            try {
                // 调用方法,拿到返回值
                object = method.invoke(bean, args);
                if (object == null){
                    continue;
                }
                // 获取方法返回类型,注册到容器中
                String beanName = MiracleUtils.createBeanName(returnType);
                MiracleUtils.registerBean(beanName, object);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        return bean;
    }

}
